package de.justphil.tcg.tcgserver.game.mechanics.game;

import java.util.HashMap;
import java.util.Map;

import de.justphil.tcg.tcgserver.game.mechanics.monster.Monster;
import de.justphil.tcg.tcgserver.game.mechanics.property.Property;
import de.justphil.tcg.tcgserver.game.mechanics.property.PropertyFactory;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class DataSerializableManager {
	private Map<Long, Monster> readMonsters;
	private Map<Long, Property> readProperties;
	private Map<Long, Monster> writtenMonsters;
	private Map<Long, Property> writtenProperties;

	public static final long NULL_ID = 0;

	public DataSerializableManager() {
		readMonsters = new HashMap<Long, Monster>();
		readProperties = new HashMap<Long, Property>();
		writtenMonsters = new HashMap<Long, Monster>();
		writtenProperties = new HashMap<Long, Property>();
	}

	public Monster readMonster(Game game, DataInput in) throws IOException {

		long id = in.readLong();
		if (id != NULL_ID) {
			Monster m = readMonsters.get(id);
			if (m == null) {
				m = new Monster(id);
				readMonsters.put(id, m);
				m.readData(game, in);
			}

			return m;
		} else {
			return null;
		}
	}

	public void writeMonster(Monster m, Game game, DataOutput out)
			throws IOException {

		if (m == null) {
			out.writeLong(NULL_ID);
		} else {
			long id = m.getId();
			out.writeLong(id);
			if (!writtenMonsters.containsKey(id)) {

				writtenMonsters.put(id, m);

				m.writeData(game, out);
			}
		}
	}

	public Property readProperty(Game game, DataInput in) throws IOException {

		long id = in.readLong();

		if (id == NULL_ID) {
			assert false;
		}
		int propertyType = in.readInt();

		Property p = readProperties.get(id);

		if (p == null) {

			/*
			 * getProperty must be started without the Game parameter so that
			 * the constructor can distinguish if the Object is created normally
			 * or by deserialization.
			 */
			p = PropertyFactory.getProperty(propertyType);
			p.setId(id);
			readProperties.put(id, p);
			p.readData(game, in);
		}

		return p;

	}

	public void writeProperty(Property p, Game game, DataOutput out)
			throws IOException {

		if (p == null) {
			assert false;
			out.writeLong(NULL_ID);
		} else {
			long id = p.getId();
			out.writeLong(id);
			out.writeInt(p.getType());
			
			assert p.getType() != Property.PROPERTY_NONE;
			
			if (!writtenProperties.containsKey(id)) {

				writtenProperties.put(id, p);

				p.writeData(game, out);
			}
		}
	}
}
